<template>
	<div class="organ-list" :style="listStyle">
		<div v-if="showTools" class="organ-list__top">
			<div class="organ-list__top-left">
				<slot name='search-tools-left'>
					<div class="count-selected" v-show="showToolsLeft">已选：{{selectedArr.length}} / {{total}}条</div>
				</slot>
			</div>
			<div class="organ-list__top-right">
				<slot name='btn-tools-left'>
					<div class="btn-tools-left"></div>
				</slot>
				<el-popover placement="bottom" trigger="click">
					<div class="organ-list_column-filter-item">
						<el-checkbox :value="isSelectAll" label="全选" @change="onColmunFilterSelectAll"></el-checkbox>
					</div>
					<div v-for="(item, index) in currentTableColumn" :key="index" class="organ-list_column-filter-item">
						<el-checkbox
							v-model="item.visible"
							:label="item.label"
							:disabled="item.required"
						></el-checkbox>
					</div>
					<w-icon
						v-show="showColumnFilterBtn"
						slot="reference"
						type="tabel-column-filter"
						class="table-column-fiter-btn"
						pointer
					></w-icon>
				</el-popover>
				<slot name='btn-tools-right'></slot>
			</div>
		</div>
		<div class="organ-list__container">
			<el-table
				ref="organTable"
				v-loading="loading"
				:data="listData"
				:expand-row-keys="expandRowKeys"
				:span-method="spanMergeHandler"
				border
				stripe
				fit
				row-key='id'
				height="100%"
				tooltip-effect="dark"
				element-loading-text="保存中"
				class="organ-table"
				:class="tableClasses"
				:cell-class-name="!wrap? 'fx-table-cell': 'fx-table-wrapcell'"
				@select="onTableRowSelect"
				@select-all="onTableRowAllSelect"
				@row-click="onTableRowClick"
				@row-dblclick="onTableRowDbclick"
				@cell-click="onCellClick"
				@sort-change="onSortChange"
				>
				<el-table-column
					v-if="selectMulity&&selectable"
					type="selection"
					width="40"
					align="center"
					reserve-selection
					class-name="table-selection"
				>
				</el-table-column>
				<el-table-column
					v-if="!selectMulity&&selectable"
					width="40"
					align="center"
					class-name="table-radio"
				>
					<template slot-scope="scope">
						<el-radio v-model="radioValue" :label="scope.row.id" @change="onRadioChange"></el-radio>
					</template>
				</el-table-column>
				<el-table-column v-if="expandRowSlot" type="expand" label="详情">
					<template slot-scope="{row, $index}">
						<el-form label-position="left" inline class="demo-table-expand" size="mini">
							<slot name="row-expand" :row="row" :$index="$index"></slot>
						</el-form>
					</template>
				</el-table-column>
				<el-table-column
					v-if="showIndex"
					label="序号"
					type="index"
					width="80"
					align="center"
				>
				</el-table-column>
				<template v-for="item in currentTableColumn">
					<el-table-column
						v-if="item.visible"
						:key="item.prop"
						:prop="item.prop"
						:label="item.label"
						:align="item.align"
						:fixed='item.fixed'
						:min-width="item.width"
						:sortable="item.sortable && 'custom'"
						:show-overflow-tooltip="item.showOverflowTooltip"
						:class-name="`fx-list-table__td ${item.className}`"
					>
					<template v-for="citem in item.childTableColumn">
					<el-table-column
						:key="citem.prop"
						:prop="citem.prop"
						:label="citem.label"
						:align="citem.align"
					>
					</el-table-column>
					</template>
					<template slot-scope="scope">
						<fx-render-dom
							v-if="item.fxRender"
							:render="item.fxRender"
							:backValue="scope"
						></fx-render-dom>
						<w-icon v-else-if="item.formatterIcon" slot='icon-slot' :type="item.iconType" size="mini" @click="editRelation(scope.row, item.prop)"></w-icon>
						<span class="fx-list-table__cell-span" v-else>{{item.formatter?item.formatter(scope.row, item.prop):scope.row[item.prop]}}</span>
					</template>
					</el-table-column>
				</template>
				<div v-if="$slots.empty" slot="empty" class="list-tabel-empty">
					<slot name="empty"></slot>
				</div>
			</el-table>
		</div>
		<div v-show="showPagination" class="organ-list__bottom">
			<w-pagination
				ref="pagination"
				:total="total"
				@on-size-change="onSizeChange"
				@on-current-change="onCurrentChange"
			></w-pagination>
		</div>
	</div>
</template>
<script>
/**
 * fx-list-table by shang 2020/12/4
 * @desc fx-list-table 表格
 * @param {tableColumn}  [Array] - 列模型
 * @param {tableColumn.prop} [String] -列的key
 * @param {tableColumn.label} [String] -列头文本
 * @param {tableColumn.width} [String] -列宽度
 * @param {tableColumn.required} [Boolean] -必选列
 * @param {tableColumn.fxRender} [Function] -render渲染
 * @param {tableColumn.click} [Function] -列点击回调
 * @param {tableColumn.rowMerge} [String] -合并单元格-row合并字段
 * @param {tableValiDate}  [Array] - 校验设置
 * @param {tableValiDate.columnProp}  [String] - 校验列key
 * @param {tableValiDate.rule}  [Function] - 校验列规则
 * @param {tableEditColumnProp}  [Array] - 可编辑列
 * @param {listData}  [Array] - 表格数据
 * @param {showPagination}  [Boolean] - 是否显示分页控件
 * @param {minWidth}  [String] - table最小宽度
 * @param {minHeight}  [String] - table最小高度
 * @param {listTotal}  [String, Number] - 数据总数
 * @param {selectable}  [Boolean] - 可选择
 * @param {selectMulity}  [Boolean] - 是否多选
 * @param {selectedRows}  [Array] - 默认选中数据
 * @param {showColumnFilterBtn}  [Boolean] - 开启列显示/隐藏控件
 * @param {showIndex}  [Boolean] - 显示索引
 * @param {loading}  [Boolean] - 显示加载中...
 * @param {expandRowSlot}  [Boolean] - 开启详情插槽
 * @param {border}  [Boolean] - 开启边框
 * @param {showTools}  [Boolean] - 开启table操作栏
 *
 * @event {change} 选项发生变化触发
 * @event {blur} 输入框失焦时触发
 * @event {focus} 输入框聚焦时触发
 */
const DEFAULT_TABLE_MIN_WIDTH = '500px'
const DEFAULT_TABLE_MIN_HEIGHT = '300px'
const DEFAULT_COL_WIDTH = '120'
const DEFAULT_COL_ALIGN = 'left'
export default {
	name: 'w-table',
	props: {
		tableColumn: {
			type: Array,
			default: () => {
				return []
			}
		},
		tableValiDate: {
			type: Array,
			default: () => {
				return []
			}
		},
		tableEditColumnProp: {
			type: Array,
			default: () => {
				return []
			}
		},
		listData: {
			type: Array,
			default: () => {
				return []
			}
		},
		showPagination: {
			type: Boolean,
			default: true
		},
		minWidth: {
			type: String,
			default: DEFAULT_TABLE_MIN_WIDTH
		},
		minHeight: {
			type: String,
			default: DEFAULT_TABLE_MIN_HEIGHT
		},
		listTotal: [String, Number],
		selectable: {
			type: Boolean,
			default: true
		},
		selectMulity: {
			type: Boolean,
			default: true
		},
		selectedRows: {
			type: Array,
			default: () => {
				return []
			}
		},
		showColumnFilterBtn: {
			type: Boolean,
			default: true
		},
		showIndex: Boolean,
		loading: Boolean,
		expandRowSlot: Boolean,
		border: {
			type: Boolean,
			default: true
		},
		showTools: {
			type: Boolean,
			default: true
		},
		showToolsLeft: {
			type: Boolean,
			default: true
		},
		wrap: {
			type: Boolean,
			default: false
		}
	},
	provide () {
		return {
			tableEventBus: this.tableEventBus
		}
	},
	data () {
		return {
			tableEventBus: this.$fxCreateEventBus(),
			currentTableColumn: [],
			total: 0,
			selectedArr: [],
			selectedRowArr: [],
			radioValue: '',
			sortParams: null,
			expandRowKeys: []
		}
	},
	computed: {
		listStyle () {
			return { 'min-width': this.minWidth, 'min-height': this.minHeight }
		},
		isSelectAll () {
			return this.currentTableColumn.every(item => {
				return !!item.visible
			})
		},
		tableClasses () {
			return {
				'no-bord': !this.border
			}
		}
	},
	created () {
		this.tableEventBus.initEvent(this, '$fx-list-cell-enter', this.onListCellEnter)
		this.tableEventBus.initEvent(this, '$fx-list-cell-up', this.onListCellUp)
		this.tableEventBus.initEvent(this, '$fx-list-cell-down', this.onListCellDown)
	},
	watch: {
		listData: {
			immediate: true,
			handler (listData) {
				listData.forEach((item, index) => {
					item.$fxIndex = index
				})
				this.$nextTick(() => {
					this.$refs.organTable.clearSelection()
					// this.selectedArr = []
					listData.forEach(item => {
						// @TODO 有bug
						this.$refs.organTable.toggleRowSelection(item, this.selectedArr.includes(item.id))
						this.$refs.organTable.toggleRowExpansion(item, this.selectedArr.includes(item.id))
					})
				})
			}
		},
		listTotal: {
			immediate: true,
			handler (val) {
				this.setPaginationTotal(val)
			}
		},
		selectedRows: {
			immediate: true,
			handler (val) {
				this.selectedRowArr = val
				this.selectedArr = val.map(item => {
					return item.id
				})
				if (val && val.length === 1) {
					this.radioValue = val[0].id
				} else {
					this.radioValue = ''
				}
				console.log(this.selectedArr)
			}
		},
		selectedRowArr (val) {
			if (this.$refs.organTable) {
				this.listData.forEach(item => {
					this.$refs.organTable.toggleRowSelection(item, this.selectedArr.includes(item.id))
				})
			}
			this.$emit('update:selectedRows', val)
		},
		tableColumn: {
			immediate: true,
			handler (val) {
				const _tableColumn = this.$fxUtils.deepClone(this.tableColumn)
				_tableColumn.forEach(item => {
					if (!this.$fxUtils.isDef(item.visible)) {
						item.visible = true
					}
					if (!this.$fxUtils.isDef(item.width)) {
						item.width = DEFAULT_COL_WIDTH
					}
					if (!this.$fxUtils.isDef(item.align)) {
						item.align = DEFAULT_COL_ALIGN
					}
					if (!this.$fxUtils.isDef(item.fixed)) {
						item.fixed = false
					}
				})
				this.currentTableColumn = _tableColumn
			}
		},
		currentTableColumn: {
			deep: true,
			handler (val) {
				this.doTableLayout()
			}
		}
	},
	methods: {
		getPaginationParams () {
			return this.$refs.pagination.getPaginationParams()
		},
		setPaginationTotal (total) {
			this.total = total - 0 || 0
		},
		setPaginationCurrent (page) {
			this.$refs.pagination.setCurrentPage(page)
		},
		onSizeChange (size) {
			this.$emit('on-size-change', size)
		},
		onCurrentChange (page) {
			this.$emit('on-current-change', page)
		},
		onTableRowSelect (selecteds, row) {
			this.selectedRowArr = selecteds
			this.selectedArr = selecteds.map(item => {
				return item.id
			})
			this.$emit('onTableRowSelect', row, this.selectedArr.includes(row.id))
		},
		onTableRowAllSelect (selecteds) {
			this.selectedRowArr = selecteds
			this.selectedArr = selecteds.map(item => {
				return item.id
			})
			this.$emit('onTableRowAllSelect', selecteds)
		},
		onRadioChange (id) {
			this.selectedArr = [].concat(this.listData.find(item => {
				return item.id === id
			}))
			this.selectedArr = [id]
		},
		getSelectedRows (validate = true) {
			return new Promise((resolve, reject) => {
				if (this.selectedRowArr.length === 0 && validate) {
					const error = '请选择一条明细'
					this.$fxMessage.warning(error)
					reject(error)
				} else {
					resolve(this.selectedRowArr)
				}
			})
		},
		getMaxSelectedFiveRow () {
			return new Promise(resolve => {
				if (this.selectedRowArr.length === 0) {
					this.$fxMessage.warning('请选择一条明细')
				} else if (this.selectedRowArr.length > 5) {
					this.$fxMessage.warning('最多选择5条明细')
				} else {
					resolve(this.selectedRowArr)
				}
			})
		},
		getSingleSelectedRow () {
			return new Promise(resolve => {
				if (this.selectedRowArr.length === 0) {
					this.$fxMessage.warning('请选择一条明细')
				} else if (this.selectedRowArr.length > 1) {
					this.$fxMessage.warning('只能选择一条明细')
				} else {
					resolve(this.selectedRowArr[0])
				}
			})
		},
		getSelectIds (fn) {
			return fn ? this.selectedRowArr.filter(fn) : this.selectedArr
		},
		clearSelected () {
			this.selectedArr = []
			this.selectedRowArr = []
			this.radioValue = ''
			this.$refs.organTable.clearSelection()
		},
		onTableRowClick (item, column, event) {
			if (!this.selectable) {
				return false
			}
			const col = this.currentTableColumn.find(item => {
				return item.prop === column.property
			}) || {}
			if (typeof col.click !== 'function') {
				this.selectMulity ? this.doSelectRow(item) : this.doSelectRowRadio(item)
			}
		},
		doSelectRow (item) {
			const index = this.selectedArr.findIndex(selectItem => {
				return item.id === selectItem
			})
			if (~index) {
				this.selectedRowArr.splice(index, 1)
			} else {
				this.selectedRowArr.push(item)
			}
			this.$refs.organTable.toggleRowSelection(item, !~index)
			this.selectedArr = this.selectedRowArr.map(item => {
				return item.id
			})
			this.$emit('onTableRowSelect', item, this.selectedArr.includes(item.id))
		},
		doSelectRowRadio (item) {
			this.radioValue = item.id
			this.selectedRowArr = [item]
			this.selectedArr = [item.id]
		},
		onColmunFilterSelectAll (visible) {
			this.currentTableColumn.forEach(item => {
				if (!item.required) {
					item.visible = visible
				}
			})
			this.doTableLayout()
		},
		doTableLayout () {
			this.$nextTick(() => {
				this.$refs.organTable.doLayout()
			})
		},
		onTableRowDbclick (item) {
			this.$emit('on-table-row-dbclick', item)
		},
		onCellClick (row, column, cell, event) {
			const col = this.currentTableColumn.find(item => {
				return item.prop === column.property
			}) || {}
			if (typeof col.click === 'function') {
				col.click(row, column, cell, event)
			}
		},
		onSortChange ({ column, prop, order }) {
			this.sortParams = order ? {
				[prop]: order === 'descending' ? 'desc' : 'asc'
			} : null
			this.$emit('on-sort-change', this.sortParams)
		},
		getSortKey () {
			return this.sortParams
		},
		getCellText (row, prop) {
			if (~prop.indexOf('.')) {
				return prop.split('.').reduce((pre, cur) => {
					return pre === undefined ? pre : pre[cur]
				}, row)
			}
			return row[prop]
		},
		async verificationRowData (row) {
			for (let i = 0; i < this.tableValiDate.length; i++) {
				try {
					await this.validate(row, this.tableValiDate[i])
				} catch (error) {
					return Promise.reject(error)
				}
			}
			return Promise.resolve(row)
		},
		validate (row, tableValiDateItem) {
			return new Promise((resolve, reject) => {
				const success = () => {
					const validate = {
						columnProp: tableValiDateItem.columnProp,
						index: row.$fxIndex,
						type: 'success'
					}
					this.tableEventBus.$emit('$fx-table-row-validate', validate)
					resolve()
				}
				const error = (message) => {
					const validate = {
						columnProp: tableValiDateItem.columnProp,
						index: row.$fxIndex,
						type: 'error',
						message
					}
					this.tableEventBus.$emit('$fx-table-row-validate', validate)
					reject(message)
				}
				tableValiDateItem.rule(row, success, error)
			})
		},
		onListCellEnter (cellEvent) {
			if (this.tableEditColumnProp.length > 0) {
				const typeIndex = this.tableEditColumnProp.findIndex(item => {
					return item === cellEvent.columnProp
				})
				if (typeIndex !== this.tableEditColumnProp.length - 1) {
					const nextType = this.tableEditColumnProp[typeIndex + 1]
					const _cellEvent = {
						columnProp: nextType,
						row: cellEvent.row,
						index: cellEvent.index
					}
					this.setListCellFocus(_cellEvent)
				} else {
					this.$emit('on-row-edit-enter')
				}
			}
		},
		setListCellFocus (cellEvent) {
			this.tableEventBus.$emit('$fx-list-cell-setfocus', cellEvent)
		},
		onListCellUp (cellEvent) {
			if (cellEvent.index <= 0) {
				return false
			}
			const index = cellEvent.index - 1
			const row = this.listData.find(item => {
				return item.$fxIndex === index
			})
			this.$emit('on-row-edit-up-down-change', row, cellEvent.columnProp)
		},
		onListCellDown (cellEvent) {
			if (cellEvent.index >= this.listData.length - 1) {
				return false
			}
			const index = cellEvent.index + 1
			const row = this.listData.find(item => {
				return item.$fxIndex === index
			})
			this.$emit('on-row-edit-up-down-change', row, cellEvent.columnProp)
		},
		scrollToBottom () {
			this.$nextTick(() => {
				const table = this.$refs.organTable
				table.bodyWrapper.scrollTop = table.bodyWrapper.scrollHeight
			})
		},
		setAllExpand () {
			this.expandRowKeys = this.listData.map(item => {
				return item.id
			})
		},
		setAllFlod () {
			this.expandRowKeys = []
		},
		spanMergeHandler ({ row, column, rowIndex, columnIndex }) {
			if (row.msg) {
				const spanArry = row.msg.filter(msg => {
					const index = msg.timeUnit.indexOf(parseInt(column.property.split('_')[1]))
					if (index !== -1) {
						return msg
					}
					// return msg.timeUnit[0] + '' === column.property.split('_')[1]
				})
				if (spanArry.length > 0) {
					if (column.property.split('_')[1] === spanArry[0].timeUnit[0] + '') {
						return {
							colspan: spanArry[0].timeUnit.length,
							rowspan: 1
						}
					} else {
						return {
							rowspan: 0,
							colspan: 0
						}
					}
				} else {
					return {
						rowspan: 1,
						colspan: 1
					}
				}
			}
			// const columnModel = this.tableColumn.find(item => {
			// 	return item.prop === column.property
			// }) || {}
			// return {
			// 	rowspan: columnModel.rowMerge ? columnModel.rowMerge : 1,
			// 	colspan: columnModel.colMerge ? columnModel.colMerge : 1
			// }
			// this.$emit('spanMergeHandler',)
		},
		editRelation (row, prop) {
			this.$emit('on-edit-relation', row, prop)
		}
	}
}
</script>
<style lang="stylus" scoped>
@import '~$assets/stylus/varsty.styl'
.organ-list {
	flex: 1
	display:flex
	flex-direction: column
	overflow: auto
	height: 100%
	&__top {
		display:flex
		flex-direction: row
		justify-content: space-between;
		margin-bottom: 10px
		&-left, &-right {
			display:flex
			flex-direction: row
			align-items: center
		}
		&-left {
			width: 150px
			.count-selected {
				margin: 0 10px
			}
		}
		&-right {
			margin-right: 26px
			flex: 1
			.btn-tools-left {
				flex: 1
			}
			.table-column-fiter-btn {
				margin: 0 20px
			}
		}
	}
	&__container {
		flex: 1
		position: relative
		>>>.el-table {
			position: absolute;
		}
	}
	&__bottom {
		height: 60px
		display: flex
		align-items: center
		justify-content: flex-end
		padding-right: 20px
	}
	>>>.organ-table {
		border: 1px solid $fxElementBorder
		&.el-table--border.no-bord {
			td, th {
				border-right-color: rgba(255,255,255,0) !important
			}
		}
		.el-table__body-wrapper::-webkit-scrollbar {
			width: 8px
			height: 8px
		}
		.el-table__body-wrapper::-webkit-scrollbar-thumb {
			border-radius: 6px;
			background-color: #E1E3E5
		}
		.el-table--border {
			td, th {
				border-right-color: white !important
			}
		}
		.fx-table-cell {
			height: 45px
			.fx-list-table__cell-span {
				white-space: nowrap
			}
		}
		.fx-table-wrapcell {
			height: 45px
		}
		.table-radio {
			.el-radio__label {
				display: none
			}
		}
		.list-tabel-empty {
			position: absolute;
			top: 0;
			left: 0;
			width: 100%;
			height: 100%;
			text-align: center;
			line-height: normal;
			display: flex;
			align-items: center;
			justify-content: center;
		}
		.el-table__expanded-cell {
			padding:5px 20px 5px 56px
			background-color: $fxGray5
		}
	}
}
.organ-list_column-filter-item {
	margin: 4px 0
	&>>>.el-checkbox__label {
		font-size: 12px
	}
}
</style>
